package ru.amse.stroganova.graph;

/**
 * 
 * This class provides a simple implementation of a directed graph.
 * 
 * @author Dasha Stroganova
 * 
 */
public class DirectedGraph extends AbstractGraph {

	@Override
	public Edge connect(Vertex source, Vertex destination) {
		return connect(source, destination, 0);
	}

	@Override
	public Edge connect(Vertex source, Vertex destination, int weight) {
		testVertexToConnect(source, destination);
		Edge edge = new Edge(source, destination, weight);
		source.addOutgoingEdge(edge);
		destination.addIncomingEdge(edge);
		return edge;
	}

	@Override
	public void addEdge(Edge edge) {
		if (!isVertexInGraph(edge.getSource()) || !isVertexInGraph(edge.getDestination())) {
			throw new IllegalArgumentException("Edge end is not in graph.");
		}
		if (areConnected(edge.getSource(), edge.getDestination())) {
			throw new IllegalArgumentException("Edge already in graph.");
		}
		edge.getSource().addOutgoingEdge(edge);
		edge.getDestination().addIncomingEdge(edge);
	}
	
	@Override
	public boolean disconnect(Vertex source, Vertex destination) {
		testVertices(source, destination);
		Edge edge = getConnectingEdge(source, destination);
		if (edge == null) {
			return false;
		}
		source.removeOutgoingEdge(edge);
		destination.removeIncomingEdge(edge);
		return true;
	}

	@Override
	public boolean removeVertex(Vertex vertex) {
		if (!isVertexInGraph(vertex)) {
			return false;
		}

		for (Edge edge : vertex.getIncomingEdges()) {
			edge.getSource().removeOutgoingEdge(edge);
		}
		for (Edge edge : vertex.getOutgoingEdges()) {
			edge.getDestination().removeIncomingEdge(edge);
		}
		removeVertexFromGraph(vertex);

		return true;
	}

	@Override
	public Edge getConnectingEdge(Vertex source, Vertex destination) {
		testVertices(source, destination);
		for (Edge edge : source.getOutgoingEdges()) {
			if (edge.getDestination().equals(destination)) {
				return edge;
			}
		}
		return null;
	}

	@Override
	public boolean isDirected() {
		return true;
	}
}
